#include "command.h"
#include <sstream>
#include <boost/foreach.hpp>
#include <google/protobuf/descriptor.h>
#include "codec.h"

google::protobuf::Message* createMessage(const std::string& name)
{
	google::protobuf::Message* message = NULL;

	const google::protobuf::Descriptor* descriptor =
		google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(name);
	if (descriptor)
	{   
		const google::protobuf::Message* prototype =
			google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
		if (prototype)
		{   
			message = prototype->New();
		}   
	}   

	return message;
}

Command::Command(): header_(NULL), body_(NULL)
{
}

Command::Command(const HeaderPtr& header)
 :header_(header), body_(NULL)
{

}

std::string Command::Encode()
{	
	if(!body_)	return std::string();

	std::string body;
	bool result = body_->SerializeToString(&body);
	if(!result || body.size() >= kBodyMaxLen) 
		return std::string();

	//TODO encrypt and zip flag
	header_->body_length = static_cast<uint16_t>(body.size());
	header_->encrypt_length = header_->body_length;
	
	std::string buff = EncodeHead();
	if(buff.empty()) return buff;	  
	
	buff.append(body);
	return buff;
}

std::string Command::EncodeHead()
{
	if(!header_) return std::string();

	std::string buff;
	buff.append(EncodeInteger<int32_t>(header_->magic_number));
	buff.append(EncodeInteger<int16_t>(header_->version));
	buff.append(EncodeInteger<int16_t>(header_->command));
	buff.append(EncodeInteger<int16_t>(header_->service_id));
	buff.append(EncodeInteger<int16_t>(header_->flag));
	buff.append(EncodeInteger<int16_t>(header_->encrypt_length));
	buff.append(EncodeInteger<int16_t>(header_->body_length));
	buff.append(header_->extend, 6);

	return buff;
}


bool Command::DecodeHead(const std::string& buff, HeaderPtr& head)
{
	if(buff.empty() || buff.size() < sizeof(Header))
		return false;

	head.reset(new Header);
	char* ptr = const_cast<char*>(buff.c_str());

	//边界值int32_t
	bool result = DecodeInteger<uint32_t>(ptr, sizeof(uint32_t), head->magic_number);
	if (!result || head->magic_number != kMagicNum )
		return false;
	
	ptr += sizeof(uint32_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->version);
	if (!result)
		return false;

	ptr += sizeof(uint16_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->command);
	if (!result)
		return false;

	ptr += sizeof(uint16_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->service_id);
	if (!result)
		return false;
	
	
	ptr += sizeof(uint16_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->flag);
	if (!result)
		return false;

	ptr += sizeof(uint16_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->encrypt_length);
	if (!result)
		return false;

	ptr += sizeof(uint16_t);
	result = DecodeInteger<uint16_t>(ptr, sizeof(uint16_t), head->body_length);
	if (!result)
		return false;

	ptr += sizeof(uint16_t);
	memcpy(head->extend, ptr, 6);
	ptr += 6;
	
	return true;
}
